package com.vogue.supplymall.order.domain.biz.impl;

import com.vogue.supplymall.common.constant.ConstantBean.EnumPaymentMode;
import com.vogue.supplymall.common.domain.dto.AlterRefundInfo;
import com.vogue.supplymall.common.domain.dto.SearchPrepayInfo;
import com.vogue.supplymall.common.domain.dto.UpdatePrepay;
import com.vogue.supplymall.common.domain.dto.UploadInfo;
import com.vogue.supplymall.common.domain.dto.UserInfo;
import com.vogue.supplymall.common.domain.tool.MessageSourceUtils;
import com.vogue.supplymall.common.domain.tool.OrderNumberGenerator;
import com.vogue.supplymall.common.exception.DataNotFindException;
import com.vogue.supplymall.common.exception.ParamErrorException;
import com.vogue.supplymall.order.domain.biz.PrepayBiz;
import com.vogue.supplymall.order.domain.biz.PrepaySearchBiz;
import com.vogue.supplymall.order.domain.biz.RefundBiz;
import com.vogue.supplymall.order.domain.model.Fulfillment;
import com.vogue.supplymall.order.domain.model.OrderBuyer;
import com.vogue.supplymall.order.domain.model.OrderItem;
import com.vogue.supplymall.order.domain.model.OrderItemProduct;
import com.vogue.supplymall.order.domain.model.OrderSeller;
import com.vogue.supplymall.order.domain.model.RefundDetail;
import com.vogue.supplymall.order.domain.model.RefundOrder;
import com.vogue.supplymall.order.domain.model.RefundPayment;
import com.vogue.supplymall.order.domain.model.RefundStatus;
import com.vogue.supplymall.order.domain.model.RefundUpload;
import com.vogue.supplymall.order.domain.service.FulfillmentService;
import com.vogue.supplymall.order.domain.service.OrderBuyerService;
import com.vogue.supplymall.order.domain.service.OrderItemProductService;
import com.vogue.supplymall.order.domain.service.OrderItemService;
import com.vogue.supplymall.order.domain.service.OrderSellerService;
import com.vogue.supplymall.order.domain.service.RefundDetailService;
import com.vogue.supplymall.order.domain.service.RefundOrderService;
import com.vogue.supplymall.order.domain.service.RefundPaymentService;
import com.vogue.supplymall.order.domain.service.RefundStatusService;
import com.vogue.supplymall.order.domain.service.RefundUploadService;
import com.vogue.supplymall.order.exception.AddExpressException;
import com.vogue.supplymall.order.exception.AddOrderException;
import com.vogue.supplymall.order.exception.OverMaxRefundCountException;
import com.vogue.supplymall.order.exception.UpdateOrderException;
import com.vogue.supplymall.upload.domain.bean.ConstantBean;
import com.vogue.supplymall.upload.domain.service.UploadService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The type Refund add biz.
 * 退货订单处理biz
 *
 * @aouthor: zhangliang
 * @date: Create in 2018-03-16
 */
@Service("refundBiz")
public class RefundBizImpl implements RefundBiz {
    /**
     * The constant LOGGER_REFUNDBIZIMPL.
     */
    public static final Logger LOGGER_REFUNDBIZIMPL = LoggerFactory.getLogger(RefundBizImpl.class);

    @Resource
    private RefundOrderService refundOrderService;
    @Resource
    private RefundStatusService refundStatusService;
    @Resource
    private RefundDetailService refundDetailService;
    @Resource
    private RefundPaymentService refundPaymentService;
    @Resource
    private RefundUploadService refundUploadService;
    @Resource
    private FulfillmentService fulfillmentService;
    @Resource
    private OrderItemService orderItemService;
    @Resource
    private OrderItemProductService orderItemProductService;
    @Resource
    private UploadService uploadService;
    @Resource
    private PrepaySearchBiz prepaySearchBiz;
    @Resource
    private MessageSourceUtils messageSourceUtils;
    @Resource
    private OrderBuyerService orderBuyerService;
    @Resource
    private OrderSellerService orderSellerService;
    @Resource
    private PrepayBiz prepayBiz;

    @Override
    @Transactional
    public Long addRefund(AlterRefundInfo alterRefundInfo, UserInfo info) {
        LOGGER_REFUNDBIZIMPL.info(" >>> add refund start >>> ");
        try {
            // 添加主退货信息
            Long refundId = insertRefundOrder(alterRefundInfo, info);
            OrderItemProduct orderItemProduct = orderItemProductService.get(alterRefundInfo.getOipid());
            // 添加退货详情
            Long refundDetailId = insertRefundDetail(alterRefundInfo, refundId, orderItemProduct);
            // 添加退货状态
            insertRefundStatus(refundId, alterRefundInfo.getCause());
            if (null != alterRefundInfo.getExpress()) {
                // 添加退货物流信息
                insertFulfillment(alterRefundInfo.getExpress(), refundId);
            }
            // 添加退货退款信息
            insertRefundPayment(alterRefundInfo, refundId);
            // 检查退单
            checkRefund(alterRefundInfo.getOiid());
            if (null != alterRefundInfo.getUploadPath()) {
                // 设置退货单上传文件
                updateRefundUpload(alterRefundInfo.getUploadPath(), refundId, refundDetailId);
            }
            LOGGER_REFUNDBIZIMPL.info(" <<< add refund end <<< ");
            return refundId;
        } catch (OverMaxRefundCountException e) {
            throw e;
        } catch (RuntimeException e) {
            throw new AddOrderException("");
        }
    }

    /**
     * check退单
     *
     * @param oiid orderitemId
     */
    private void checkRefund(Long oiid) {
        OrderItem orderItem = orderItemService.get(oiid);
        String sql = "select SUM(rd.refundquantity) refundquantity from refund_detail rd,refund_status rs "
                + "where rd.refundid=rs.refundid and rs.refundstatus <> 2 and rd.oiid = " + oiid;
        Integer sum = null;
        List<Map<String, Object>> list = refundDetailService.query(sql);
        for (Map<String, Object> map : list) {
            sum = Integer.parseInt(String.valueOf(map.get("refundquantity")));
        }
        if (null != sum) {
            if (orderItem.getItemquantity() < sum) {
                throw new OverMaxRefundCountException("");
            }
        }

    }

    /**
     * insert退货订单信息
     *
     * @param alterRefundInfo alterRefundInfo
     * @param info            info
     * @return 退单id
     */
    private Long insertRefundOrder(AlterRefundInfo alterRefundInfo, UserInfo info) {
        LOGGER_REFUNDBIZIMPL.info("refund -> 添加退货订单信息");
        RefundOrder refundOrder = new RefundOrder();
        refundOrder.setOrderid(alterRefundInfo.getOrderid());
        refundOrder.setCause(alterRefundInfo.getCause());
        refundOrder.setRefundway(alterRefundInfo.getRefundway());
        refundOrder.setSyscodeid(info.getSyscodeid());
        refundOrder.setRefundnumber(OrderNumberGenerator.getter(OrderNumberGenerator.EnumOrderNumberType.BACK));
        if (StringUtils.isNotEmpty(alterRefundInfo.getMemo())) {
            refundOrder.setMemo(alterRefundInfo.getMemo());
        } else {
            refundOrder.setMemo("");
        }
        // 20180917 如果是差异自动退货，自动退货flag设置1
        if (alterRefundInfo.getCause() == 6) {
            refundOrder.setAutoflag(true);
        }
        refundOrder.setFreight(BigDecimal.ZERO);
        refundOrder.setFinalprice(new BigDecimal(alterRefundInfo.getRefundprice()));
        refundOrder.setDisabledflag(false);
        refundOrder = refundOrderService.save(refundOrder);
        return refundOrder.getId();
    }

    /**
     * insert退货订单详细
     *
     * @param alterRefundInfo  alterRefundInfo
     * @param refundId         refundId
     * @param orderItemProduct orderItemProduct
     * @return 退单详情id
     */
    private Long insertRefundDetail(AlterRefundInfo alterRefundInfo, Long refundId, OrderItemProduct orderItemProduct) {
        LOGGER_REFUNDBIZIMPL.info("refund -> 添加退货订单详细信息");
        RefundDetail refundDetail = new RefundDetail();
        refundDetail.setOiid(alterRefundInfo.getOiid());
        refundDetail.setOipid(alterRefundInfo.getOipid());
        refundDetail.setRefundid(refundId);
        refundDetail.setRefundprice(orderItemProduct.getPrice());
        refundDetail.setRefundquantity(alterRefundInfo.getRefundquantity());
        refundDetail = refundDetailService.save(refundDetail);
        return refundDetail.getId();
    }

    /**
     * insert退货订单状态
     *
     * @param refundId 退单id
     * @param cause    退货原因
     */
    private void insertRefundStatus(Long refundId, Integer cause) {
        LOGGER_REFUNDBIZIMPL.info("refund -> 添加退货订单状态信息");
        RefundStatus refundStatus = new RefundStatus();
        // 20180917 如果是差异自动退货
        if (cause == 6) {
            refundStatus.setRefundstatus(3);
        } else {
            refundStatus.setRefundstatus(0);
        }
        refundStatus.setRefundid(refundId);
        refundStatus.setSellerpullstate(0);
        refundStatus.setBuyerpullstate(0);
        refundStatus.setMemo("");
        refundStatusService.save(refundStatus);
    }

    /**
     * insert物流信息
     *
     * @param express  物流信息
     * @param refundId 退单id
     * @return 物流id
     */
    private Long insertFulfillment(Map<String, String> express, Long refundId) {
        LOGGER_REFUNDBIZIMPL.info("refund -> 添加物流信息");
        if (StringUtils.isNotEmpty(express.get("number"))) {
            LOGGER_REFUNDBIZIMPL.info("refund -> 添加物流信息 -> success");
            Fulfillment fulfillment = new Fulfillment();
            fulfillment.setOrderid(refundId);
            fulfillment.setType(0);
            fulfillment.setStatus(1);
            if (StringUtils.isNotEmpty(express.get("number"))) {
                fulfillment.setNumber(express.get("number"));
            } else {
                fulfillment.setNumber("");
            }
            if (StringUtils.isNotEmpty(express.get("companycode"))) {
                fulfillment.setCompanycode(express.get("companycode"));
            } else {
                fulfillment.setCompanycode("");
            }
            fulfillment.setSenddate(null);
            fulfillment.setArrivedate(null);
            fulfillment = fulfillmentService.save(fulfillment);
            return fulfillment.getId();
        } else {
            LOGGER_REFUNDBIZIMPL.info("refund -> 添加物流信息 -> number is null,insert cancel.");
            return -1L;
        }
    }

    /**
     * 添加退单支付信息
     *
     * @param alterRefundInfo alterRefundInfo
     * @param refundId        退单id
     */
    private void insertRefundPayment(AlterRefundInfo alterRefundInfo, Long refundId) {
        LOGGER_REFUNDBIZIMPL.info("refund -> 添加退货支付信息");
        RefundPayment refundPayment = new RefundPayment();
        refundPayment.setRefundid(refundId);
        refundPayment.setAmount(new BigDecimal(alterRefundInfo.getRefundprice()));
        refundPayment.setArchivestatus(false);
        refundPayment.setPaymentmode(alterRefundInfo.getRefundway());
        refundPayment.setPaymentdate(null);
        refundPayment.setPaymentnumber("");
        if (alterRefundInfo.getRefundway() == 0) {
            refundPayment.setPaymenttype(0);
        } else {
            refundPayment.setPaymenttype(1);
        }
        refundPaymentService.save(refundPayment);
    }

    /**
     * 上传退单信息
     *
     * @param uploadPath     上传路径
     * @param refundId       退单id
     * @param refundDetailId 退单详情id
     */
    private void updateRefundUpload(String[] uploadPath, Long refundId, Long refundDetailId) {
        LOGGER_REFUNDBIZIMPL.info("refund -> 添加上传文件信息");
        for (String str : uploadPath) {
            RefundUpload refundUpload = new RefundUpload();
            refundUpload.setRefundid(refundId);
            refundUpload.setRefunddetailid(refundDetailId);
            refundUpload.setUrl(str.replace(File.separator, "/"));
            refundUpload.setSize(0);
            refundUpload.setType(0);
            refundUploadService.save(refundUpload);
            //如果发现图片是临时路径则重新上传生成正式的
            if (refundUpload.getUrl().contains("/"
                    + com.vogue.supplymall.common.constant.ConstantBean.SYSTEM_NAME
                    + "/" + UploadService.TEMP_PATH)) {
                UploadInfo uploadInfo = new UploadInfo();
                uploadInfo.setDataid(refundUpload.getId());
                uploadInfo.setSourcepath(refundUpload.getUrl());
                if (refundUpload.getUrl().contains(".")) {
                    uploadInfo.setExtension(refundUpload.getUrl().substring(refundUpload.getUrl().lastIndexOf(".")) + 1);
                }
                uploadInfo.setModuleName(
                        ConstantBean.REFUND_MODULE_NAME
                                + "/" + refundUpload.getRefundid()
                                + "/" + refundUpload.getRefunddetailid());
                uploadService.uploadResource(uploadInfo);
            }
        }
    }

    @Override
    @Transactional
    public Boolean updateRefund(AlterRefundInfo alterRefundInfo, UserInfo info) {
        LOGGER_REFUNDBIZIMPL.info(">>> updateRefund 更新退货信息");
        try {
            RefundStatus refundStatus = refundStatusService.get(alterRefundInfo.getRefundstatusid());
            if (null == refundStatus) {
                throw new DataNotFindException("");
            }
            RefundOrder refundOrder = refundOrderService.get(refundStatus.getRefundid());
            if (null == refundOrder) {
                throw new DataNotFindException("");
            }
            //如果是完成则看看退款方式是什么，进行对应处理
            if (alterRefundInfo.getAction() == 3) {
                RefundPayment refundPayment = refundPaymentService.selectOneByWhr("refundid=" + refundStatus.getRefundid());
                refundPayment.setPaymentdate(new Date());
                refundPayment.setModifyDate(new Date());
                refundPayment.setArchivestatus(true);
                refundPayment.setPaymentmode(alterRefundInfo.getRefundway());
                refundPaymentService.update(refundPayment);
                if (alterRefundInfo.getRefundway() == 4) {
                    returnPrepay(refundOrder.getOrderid(), refundOrder.getId(), refundPayment.getAmount(), info);
                }
            }
            refundStatus.setRefundstatus(alterRefundInfo.getAction());
            refundStatus.setModifyDate(new Date());
            refundStatusService.update(refundStatus);
        } catch (RuntimeException r) {
            throw new UpdateOrderException("");
        }

        return true;
    }

    @Override
    public void returnPrepay(Long orderid, Long refundid, BigDecimal amount, UserInfo info) {
        if (null != info.getAccountid() || info.getAccountid() > 0L) {
            OrderBuyer orderBuyer = orderBuyerService.selectOneByWhr("orderid=" + orderid);
            OrderSeller orderSeller = orderSellerService.selectOneByWhr("orderid=" + orderid);
            UpdatePrepay updatePrepay = new UpdatePrepay();
            updatePrepay.setAccountid(info.getAccountid());
            updatePrepay.setOrderid(orderid);
            updatePrepay.setRefundid(refundid);
            updatePrepay.setType(4); //0：线下 1：吾享 2：微信 3：支付宝 4:预付货款
            updatePrepay.setOrigin(2); // 1-云供应链 2-采购平台
            updatePrepay.setAmount(amount);
            updatePrepay.setBuysyscodeid(orderBuyer.getSyscodeid());
            updatePrepay.setBuyorganid(orderBuyer.getOrganid());
            updatePrepay.setSellsyscodeid(orderSeller.getSyscodeid());
            updatePrepay.setSellorganid(orderSeller.getOrganid());
            prepayBiz.updatePrepay(updatePrepay);
        } else {
            LOGGER_REFUNDBIZIMPL.error("无法退款到预付货款，因为没有预付货款账户！企业名称={}，LOGinid={}", info.getEntName(), info.getLoginId());
            throw new UpdateOrderException("");
        }
    }


    @Override
    @Transactional
    public Long updateFulfillment(AlterRefundInfo alterRefundInfo) {
        Map<String, String> express = alterRefundInfo.getExpress();
        if (!express.containsKey("number")) {
            throw new ParamErrorException("");
        }
        if (!express.containsKey("companycode")) {
            express.put("companycode", "");
        }
        if (null == alterRefundInfo.getExpress().get("id")) {
            LOGGER_REFUNDBIZIMPL.info(">>> updateFulfillment 更新物流信息");
            if (fulfillmentService.getFulfillmentForRefund(new Long(alterRefundInfo.getRefundid())) > 0) {
                LOGGER_REFUNDBIZIMPL.info(">>> 物流信息已存在");
                throw new AddExpressException("");
            } else {
                try {
                    return insertFulfillment(alterRefundInfo.getExpress(), alterRefundInfo.getRefundid());
                } catch (RuntimeException e) {
                    throw new UpdateOrderException("");
                }
            }
        } else {
            if (StringUtils.isNotEmpty(express.get("number"))) {
                try {
                    Fulfillment fulfillment = fulfillmentService.get(new Long(express.get("id")));
                    if (null == fulfillment) {
                        throw new UpdateOrderException("");
                    }
                    fulfillment.setNumber(express.get("number"));
                    fulfillment.setCompanycode(express.get("companycode"));
                    fulfillment.setModifyDate(new Date());
                    fulfillmentService.update(fulfillment);
                    return fulfillment.getId();
                } catch (RuntimeException e) {
                    throw new UpdateOrderException("");
                }
            } else {
                throw new ParamErrorException("");
            }
        }
    }

    @Override
    public List<Map<String, Object>> refundMode(Long orderid) {
        OrderSeller orderSeller = orderSellerService.selectOneByWhr("orderid=" + orderid);
        OrderBuyer orderBuyer = orderBuyerService.selectOneByWhr("orderid=" + orderid);
        SearchPrepayInfo searchPrepayInfo = new SearchPrepayInfo();
        searchPrepayInfo.setSyscodeid(orderBuyer.getSyscodeid());
        searchPrepayInfo.setOrganid(orderBuyer.getOrganid());
        searchPrepayInfo.setSellsyscodeid(orderSeller.getSyscodeid());
        searchPrepayInfo.setSellorganid(orderSeller.getOrganid());
        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("id", EnumPaymentMode.UnderLine.getCode());
        map.put("name", messageSourceUtils.getMessage("global.paymentmode." + EnumPaymentMode.UnderLine.getCode(), null));
        list.add(map);
        if (prepaySearchBiz.existAccountPrepay(searchPrepayInfo)) {
            map = new HashMap<>();
            map.put("id", EnumPaymentMode.AdvancePayment.getCode());
            map.put("name", messageSourceUtils.getMessage("global.paymentmode." + EnumPaymentMode.AdvancePayment.getCode(), null));
            list.add(map);
        }
        return list;
    }

}
